﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Newtonsoft.Json;
using RemotingLibs.QuoteClass;
using TdxApiPool.Common.Provider;
using TdxApiPool.Connect;
using TdxApiPool.ErrorHandler;

namespace TdxApiPool.Looper
{
    public class QueueLooper
    {
        private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(QueueLooper));

        public bool Stop = false;
        public Queue Queue = new Queue();
        public TdxConnection TdxConnection;

        private static readonly QueueLooper Instance = new QueueLooper();
        private static readonly object LockObj = new object();

        public static QueueLooper GetInstance()
        {
            return Instance;
        }


        private QueueLooper()
        {
        }

        public void Run()
        {
            while (!Stop)
            {
                List<QuoteRtN> dequeue = null;

                try
                {
                    Monitor.Enter(LockObj);
                    if (Queue.Count == 0)
                    {
                        Monitor.Wait(LockObj);
                    }
                    dequeue = (List<QuoteRtN>) Queue.Dequeue();
                }
                catch (Exception e)
                {
                    // ignored
                }
                finally
                {
                    Monitor.Exit(LockObj);
                }

                var quoteRts = new List<QuoteRtN>();

                if (dequeue != null)
                    foreach (QuoteRtN quoteRt in dequeue)
                    {
                        if (!SanpshootService.Snapshoot.ContainsKey(quoteRt.StkCode))
                        {
                            quoteRts.Add(quoteRt);
                            SaveSnapshoot(quoteRt);
                            continue;
                        }

                        QuoteRtN data = SanpshootService.Snapshoot.GetOrAdd(quoteRt.StkCode, quoteRt);

                        if (Math.Abs(quoteRt.VolAll) <= 0)
                        {
                            var quoteRtBsize1 = quoteRt.Bsize1;
                            var quoteRtAsize1 = quoteRt.Asize1;
                            var max = Math.Max(quoteRtBsize1, quoteRtAsize1);

                            var dataBsize1 = data.Bsize1;
                            var dataAsize1 = data.Asize1;
                            var oldMax = Math.Max(dataBsize1, dataAsize1);

                            //当匹配量比旧数据大的时候才推出去
                            if (oldMax > max)
                            {
                                //保存截面
                                SaveSnapshoot(quoteRt);
                                quoteRts.Add(quoteRt);
                            }
                            continue;
                        }

                        if (quoteRt.VolAll <= data.VolAll)
                        {
                            continue;
                        }

                        quoteRts.Add(quoteRt);
                        SaveSnapshoot(quoteRt);
                    }

                //批量推送与保存
                if (quoteRts.Count != 0)
                {
                    SaveHq(quoteRts);
                    _log.Debug("source data count = " + dequeue.Count + "\tnew data count = " + quoteRts.Count);
                }
            }
        }

        private static void SaveSnapshoot(QuoteRtN quoteRt)
        {
            SanpshootService.Snapshoot.AddOrUpdate(quoteRt.StkCode, quoteRt, (k, v) => quoteRt);
            DateTime nowTime = DateTime.Now;
            DateTime oldTime = SanpshootService.SnapshootUpdateTime.GetOrAdd(quoteRt.StkCode, nowTime);

            //计算更新延迟
            var delay = nowTime.Ticks - oldTime.Ticks;
            SanpshootService.SnapshootUpdateDelay.AddOrUpdate(quoteRt.StkCode, delay, (k, v) => delay);
            SanpshootService.SnapshootUpdateTime.AddOrUpdate(quoteRt.StkCode, nowTime, (k, v) => nowTime);
        }


        private void SaveHq(List<QuoteRtN> quoteRt)
        {
            try
            {
                Dictionary<uint, string> dictionary =
                    quoteRt.ToDictionary(m => m.StkCode, m => JsonConvert.SerializeObject(m));
//                HqRedisProvider.SaveHq(dictionary);
                HqRedisProvider.PushHq(quoteRt);
            }
            catch (Exception e)
            {
                _log.Error("行情队列，redis存储错误");
                _log.Error(e);
                EmailSenter.SendEmail("redis存储错误", "行情队列，redis存储错误\n" + "exctption:" + e.Message + quoteRt);
            }
        }

        public void AddData(List<QuoteRtN> quoteRts)
        {
            try
            {
                Monitor.Enter(LockObj);
                Queue.Enqueue(quoteRts);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            finally
            {
                Monitor.Pulse(LockObj);
                Monitor.Exit(LockObj);
            }
        }
    }
}